home *** CD-ROM | disk | FTP | other *** search
/ AI Game Programming Wisdom / AIGameProgrammingWisdom.iso / SourceCode / 04 Pathfinding and Movement / 06 Scutt / Listing1.cpp
Encoding:
Text File  |  2001-12-09  |  5.0 KB  |  161 lines

  1. /* Copyright (C) Tom Scutt and Core Design Ltd, 2001. 
  2.  * All rights reserved worldwide.
  3.  *
  4.  * This software is provided "as is" without express or implied
  5.  * warranties. You may freely copy and compile this source into
  6.  * applications you distribute provided that the copyright text
  7.  * below is included in the resulting source code, for example:
  8.  * "Portions Copyright (C) Tom Scutt and Core Design Ltd, 2001"
  9.  */
  10.  
  11. // Swarm update. (Code reproduced by kind permission of Core Design Ltd.)
  12.  
  13. void UpdateAgents()
  14. {
  15.     AGENT_STRUCT    *agent;
  16.     long    h, i, angle, dx, dy, dz, oldx, oldy, oldz;
  17.  
  18.     agent = &agents[0];
  19.  
  20.     for (i=0;i<MAX_AGENTS;i++,agent++)
  21.     {
  22.         //for each agent, check to see if it's active 
  23.         if (agent->active)
  24.         {
  25.             //remember its current position
  26.             oldx = agent->xpos;
  27.             oldy = agent->ypos;
  28.             oldz = agent->zpos;
  29.  
  30.             //update x and z pos depending on y-rotation and speed
  31.             agent->xpos += agent->speed * SIN(agent->yrot);
  32.             agent->zpos += agent->speed * COS(agent->yrot);
  33.  
  34.             //update y depending on fallspeed
  35.             agent->ypos += agent->fallspeed;
  36.  
  37.             //update fallspeed by adding gravity
  38.             agent->fallspeed += GRAVITY;
  39.  
  40.             //calculate the difference between the agent's 
  41.             //position and the target position 
  42.             dz = target->zpos - agent->zpos;
  43.             dy = target->ypos - agent->ypos;
  44.             dx = target->xpos - agent->xpos;
  45.  
  46.             //work out the *relative* angle of the target to the agent
  47.             //if it's time for the agent to flee, reverse the angle
  48.             //It's a good idea to initialize agents with the timer 
  49.             //set to a small random value. That way, the swarm will 
  50.             //gradually disperse over time.
  51.             if (agent->timer < (RAT_LIFE_TIME - RAT_FLEE_TIME))
  52.                 angle = ATAN(dz, dx) - agent->yrot;
  53.             else 
  54.                 angle = agent->yrot - ATAN(dz, dx);
  55.  
  56.             //It wasn't done here, but one could influence 
  57.             //the swarm depending on the way the player is facing.
  58.             //One could also extrapolate player movement to set up the 
  59.             //player's likely future position as the target
  60.  
  61.             //Hit the player if within range 
  62.             //(using your favored collision method)
  63.             //Here: a simple collision box.
  64.             if (abs(dz) < AGENT_HIT_RANGE && abs(dy) < AGENT_HIT_RANGE 
  65.                 && abs(dx) < AGENT_HIT_RANGE)
  66.                 {target->hp-=AGENT_DAMAGE;}
  67.  
  68.             if (!agent->falling) 
  69.             // steer because not the agent is not falling 
  70.             {
  71.                 //if the target is outside your set range, 
  72.                 //go (roughly) towards it
  73.                 if (abs(dz) + abs(dx) > SWARM_RANGE) 
  74.                 {
  75.                     //increase speed to the maximum for this creature
  76.                     //give each creature a slightly different maximum
  77.                     //(done here by & the index with 0x1f)
  78.  
  79.                     if (agent->speed < 24 + (i & 0x1f))
  80.                         agent->speed++;
  81.  
  82.                     if (abs(angle) < AGENT_LOCK_ANGLE)
  83.                     {
  84.                         //vary the steering each cycle - more organic
  85.                         agent->yrot += (global_counter - i) << 3;
  86.                     }
  87.                     else if (angle < 0)
  88.                         agent->yrot -= AGENT_TURN_SPEED<<1;
  89.                     else
  90.                         agent->yrot += AGENT_TURN_SPEED<<1;
  91.                 }
  92.                 else
  93.                 //if the target is roughly within a short range, 
  94.                 //swirl around it
  95.                 {
  96.                     if (agent->speed & 0x1)
  97.                         agent->yrot += AGENT_TURN_SPEED;
  98.                     else
  99.                         agent->yrot -= AGENT_TURN_SPEED;
  100.  
  101.                     //play around with the numbers in this next line 
  102.                     //to get a variety of different behaviors
  103.                     agent->speed = 48 - (abs(angle) >> 10);
  104.  
  105.                 }
  106.             }
  107.             //end of steering
  108.  
  109.             h = FloorHeight(agent->x_pos,agent->y_pos,agent->z_pos);
  110.             if (h < agent->ypos - AGENT_MAX_STEP)
  111.             //If the agent's new position would be much higher 
  112.             //than its current position, bounce it off the wall 
  113.             //by resetting its position and changing its angle
  114.             {
  115.                 //if the agent hits a wall while it's fleeing, 
  116.                 //deactivate it. This looks fine with small creatures
  117.                 if (agent->timer > (AGENT_LIFE_TIME - AGENT_FLEE_TIME))
  118.                     agent->active = 0;
  119.  
  120.                 if (angle > 0)
  121.                     agent->yrot += 180_DEGREES;
  122.                 else
  123.                     agent->yrot -= 180_DEGREES;
  124.                 agent->xpos = oldx;
  125.                 agent->ypos = oldy;
  126.                 agent->zpos = oldz;
  127.                 agent->fallspeed = 0;
  128.             }
  129.             //If the agent's new position would take it onto a 
  130.             //block of climbable height, angle its body upward,
  131.             //reset its x and z position and move it upwards
  132.             else if (h < agent->ypos - AGENT_IGNORE_STEP)
  133.             {
  134.                 fx->pos.x_rot = AGENT_CLIMB_ANGLE;
  135.                 fx->pos.x_pos = oldx;
  136.                 fx->pos.y_pos = oldy - AGENT_CLIMB_SPEED;
  137.                 fx->pos.z_pos = oldz;
  138.                 fx->fallspeed = 0;
  139.             }
  140.              else if (agent->ypos > h)
  141.             //the agent is below the floor surface, so move it up to //the floor, reset its fallspeed and set falling to 0. //This happens every cycle the agent isn't in the air //(as we always try to change the y-pos due to gravity)
  142.             {
  143.                 agent->ypos = h;
  144.                 agent->fallspeed = 0;
  145.                 agent->falling = 0;
  146.             }
  147.  
  148.             if (agent->fallspeed < AGENT_MAX_FALLSPEED && 
  149.                 agent->timer < AGENT_LIFE_TIME)
  150.             //tilt things as they fall
  151.                 agent->xrot = -(agent->fallspeed << 6);
  152.             else
  153.             //if they fall too fast or time's run out, kill them
  154.                 next_agent = agent->active = 0;
  155.  
  156.             agent->timer++;
  157.  
  158.         }
  159.     }
  160. }
  161.